/*
 * Configuration.h
 *
 *  Created on: Sep 23, 2011
 *      Author: erudhes
 */
#ifndef CONFIGURATION_H_
#define CONFIGURATION_H_
#ifdef __WXGTK__
#include <netinet/in.h>
#endif
#include <map>
#include <vector>
#include <wx/wx.h>

class wxXmlNode;
class wxXmlDocument;

namespace Configuration
{
	/**
	 * This class is holding configuration data related to one vehicle on a level
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 1.0
	 * @since 2012-03-08
	 * */
	class Vehicle
	{
		public:
			/**
			 * The only constructor takes the XML node and reads every data into its data members
			 *
			 * @param node The XML node containing the network configuration
			 */
			Vehicle(wxXmlNode* node);
			virtual ~Vehicle();
			const wxString& getName() const;
			void setName(const wxString& name);
			const wxPoint& getPosition() const;
			void setPosition(const wxPoint& position);
			/**
			 * Caches the given position, but will not be written to the xml file
			 *
			 * @param position The position to be cached
			 */
			void cachePosition(const wxPoint& position);
			/**
			 * Clears the cashed position
			 */
			void resetCache();

		private:
			wxString mName;
			wxPoint mPosition;
			wxPoint mCachedPosition;
			wxXmlNode* mNode;
	};

	/**
	 * This class is holding configuration data related to a separate level
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 1.0
	 * @since 2012-03-08
	 */
	class Level
	{
		public:
			/**
			 * The only constructor takes the XML node and reads every data into its data members
			 *
			 * @param node The XML node containing the network configuration
			 */
			Level(wxXmlNode* node);
			virtual ~Level();
			const wxString& getName() const;
			void setName(const wxString& name);
			Vehicle* getVehicleA();
			Vehicle* getVehicleB();

		private:
			wxString mName;
			Vehicle* mVehicleA;
			Vehicle* mVehicleB;
			wxXmlNode* mNode;
	};

	/**
	 * This class is holding configuration data related to the levels
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 1.0
	 * @since 2012-03-08
	 */
	class Levels
	{
		public:
			/**
			 * The only constructor takes the XML node and reads every data into its data members
			 *
			 * @param node The XML node containing the network configuration
			 */
			Levels(wxXmlNode* node);
			virtual ~Levels();
			const wxString& getPath() const;
			void setPath(const wxString& path);
			Level* getLevel(const wxString& name);
			/**
			 * This method creates a new level and the xml representation for it.
			 *
			 * It is the caller's responsibility to fill up the level with correct values - only the name property is filled up
			 * The new Level object is inserted into the list of levels
			 *
			 * @param name The name of the new level
			 * @return A new empty Level object
			 */
			Level* createNewLevel(const wxString& name);
			/**
			 * This method adds a new level to the configuration.
			 *
			 * This method assumes that the level has been added since the last start of the application - e.g.: The level has been downloaded from a server -, so everything.
			 * is OK with this level. The config file and the bmp file and the thumbnails as well. The new Level object is inserted into the list of levels
			 *
			 * @param name The name of the level to be added
			 * @return The newly created Level object. It is filled up with the needed informations.
			 */
			Level* addNewLevel(const wxString& name);
			unsigned int getNumberOfLevels() const;
			std::vector<wxString> getLevelNames() const;

		private:
			struct LevelData
			{
				Level* mLevel;
				wxXmlDocument* mConfigFile;
			};
			wxString mPath;
			std::map<wxString, LevelData> mLevels;
			wxXmlNode* mNode;
	};

	/**
	 * This class holds the address of the proxy from the configuration data
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 2.0
	 * @since 2012-05-19
	 */
	class ProxyAddress
	{
		public:
			/**
			 * The only constructor takes the XML node and reads every data into its data members
			 *
			 * @param node The XML node containing the network configuration
			 */
			ProxyAddress(wxXmlNode* node);
			virtual ~ProxyAddress();
			const wxString& getHost();
			void setHost(const wxString& host);
			int getPort();
			void setPort(int port);

		private:
			wxString mHost;
			int mPort;
			wxXmlNode* mNode;
	};

	/**
	 * This class holds the proxy related configuration data
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 2.0
	 * @since 2012-05-19
	 */
	class ProxyConfiguration
	{
		public:
			/**
			 * The only constructor takes the XML node and reads every data into its data members
			 *
			 * @param node The XML node containing the network configuration
			 */
			ProxyConfiguration(wxXmlNode* node);
			virtual ~ProxyConfiguration();
			bool useProxy() const;
			void setUseProxy(bool useProxy);
			ProxyAddress* getProxyAddress() const;

		private:
			bool mUseProxy;
			ProxyAddress* mProxyAddress;
			wxXmlNode* mNode;
	};

	/**
	 * This class is holding every network related configuration data
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 1.0
	 * @since 2012-03-08
	 */
	class NetworkConfiguration
	{
		public:
			/**
			 * The only constructor takes the XML node and reads every data into its data members
			 *
			 * @param node The XML node containing the network configuration
			 */
			NetworkConfiguration(wxXmlNode* node);
			virtual ~NetworkConfiguration();
			int getPortNumber() const;
			void setPortNumber(int portNumber);
			int getFrequency() const;
			void setFrequency(int frequency);
			/**
			 * Cashes the given frequency, but will not be written to the xml file
			 *
			 * @param frequency The new frequency to be cached
			 */
			void cacheFrequency(int frequency);
			/**
			 * Clears the cached frequency value
			 */
			void resetCache();
			bool fetchOnlyFreeServers() const;
			void fetchOnlyFreeServers(bool fetchOnlyFreeServers);
			bool downloadUnknownLevels() const;
			void downloadUnknownLevels(bool downloadUnknownLevels);
			bool uploadLevels() const;
			void uploadLevels(bool uploadLevels);
			bool registerServer();
			void registerServer(bool registerServer);
			ProxyConfiguration* getProxyConfiguration();

		private:
			int mPortNumber;
			int mFrequency;
			int mCachedFrequency;
			bool mFetchOnlyFreeServers;
			bool mDownloadUnknownLevels;
			bool mUploadLevels;
			bool mRegisterServer;
			ProxyConfiguration* mProxyConfiguration;
			wxXmlNode* mNode;
	};

	/**
	 * This class holds every configuration related data. It is a singleton class.
	 *
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 1.0
	 * @since 2012-03-08
	 */
	class Configuration
	{
		public:
			/**
			 * This method updates the value of the XML node
			 *
			 * The method searches for the correct node with the name and properties under a certain XML node
			 *
			 * @param parent The XML node which contains the node to update. It is the parent node.
			 * @param nodeName The name of the node to update
			 * @param nodeContent The new content of the node
			 * @param properties List of properties in key-value pairs of the node to update
			 * @return true if the node found an updated, false otherwise
			 */
			static bool updateNodeContent(wxXmlNode* parent, const wxString& nodeName, const wxString& nodeContent, const std::map<wxString, wxString>& properties = std::map<wxString, wxString>());
			/**
			 * Default constructor of the class. Reads and parses the configuration files
			 */
			Configuration();
			virtual ~Configuration();
			const wxString& getLogoPath() const;
			void setLogoPath(const wxString& logoPath);
			int getDotSize() const;
			void setDotSize(int dotSize);
			/**
			 * Cashes the given dot size, but will not be written to the xml file
			 *
			 * @param dotSize The new dot size to be cached
			 */
			void cacheDotSize(int dotSize);
			/**
			 * Clears the cached dot size
			 */
			void resetCache(bool deepReset = true);
			NetworkConfiguration* getNetworkConfiguration();
			Levels* getLevels();

		private:
			wxString mLogoPath;
			int mDotSize;
			int mCachedDotSize;
			NetworkConfiguration* mNetworkConfiguration;
			Levels* mLevels;
			wxXmlDocument* mXmlConfig;
	};

	/**
	 * This is a helper class to negotiate configuration between the server and the client
	 *
	 * This class holds every information needed to negotiate the configuration during game start, and can be easily
	 * send to the other side over the network.
	 * @author Rudolf Heszele heszele@gmail.com
	 * @version 2.0
	 * @since 2012-05-19
	 */
	class CommonConfigurationPacket
	{
		public:
			/**
			 * This constructor is used on the server side to create the packet with the current configuration data
			 *
			 * The constructor reads every needed information from the configuration and stores them in its data members
			 * @param configuration The singleton class holding every configuration information
			 * @param level The name of the level which ones configuration needs to be negotiated
			 */
			CommonConfigurationPacket(Configuration* configuration, const wxString& level);
			/**
			 * This constructor is used on the client side to create the packet from the received data from the network
			 *
			 * @param buffer The received raw data from the server
			 */
			CommonConfigurationPacket(const char* buffer);
			~CommonConfigurationPacket();
			int getDotSize();
			int getFrequency();
			wxPoint getVehiclePositionA();
			wxPoint getVehiclePositionB();

		private:
			int mDotSize;
			int mFrequency;
			int mCoordinateAx;
			int mCoordinateAy;
			int mCoordinateBx;
			int mCoordinateBy;
	};

/**
 * Vehicle class
 */

	inline const wxString& Vehicle::getName() const
	{
		return mName;
	}

	inline const wxPoint& Vehicle::getPosition() const
	{
		return mCachedPosition;
	}

	inline void Vehicle::cachePosition(const wxPoint& position)
	{
		mCachedPosition = position;
	}

	inline void Vehicle::resetCache()
	{
		mCachedPosition = mPosition;
	}

/**
 * Level class
 */

	inline const wxString& Level::getName() const
	{
		return mName;
	}

	inline Vehicle* Level::getVehicleA()
	{
		return mVehicleA;
	}

	inline Vehicle* Level::getVehicleB()
	{
		return mVehicleB;
	}

/**
 * Levels class
 */

	inline const wxString& Levels::getPath() const
	{
		return mPath;
	}

	inline Level* Levels::getLevel(const wxString& name)
	{
		if(mLevels.end() == mLevels.find(name))
			return NULL;
		return mLevels[name].mLevel;
	}

	inline unsigned int Levels::getNumberOfLevels() const
	{
		return mLevels.size();
	}

	inline std::vector<wxString> Levels::getLevelNames() const
	{
		std::vector<wxString> returnVector;

		returnVector.reserve(this->getNumberOfLevels());
		for(std::map<wxString, LevelData>::const_iterator levelsIterator = mLevels.begin(); levelsIterator != mLevels.end(); levelsIterator++)
			returnVector.push_back(levelsIterator->first);

		return returnVector;
	}

/**
 * ProxyAddress class
 */

	inline const wxString& ProxyAddress::getHost()
	{
		return mHost;
	}

	inline int ProxyAddress::getPort()
	{
		return mPort;
	}

/**
 * ProxyConfiguration class
 */

	inline bool ProxyConfiguration::useProxy() const
	{
		return mUseProxy;
	}

	inline ProxyAddress* ProxyConfiguration::getProxyAddress() const
	{
		return mProxyAddress;
	}

/**
 * NetworkConfiguration class
 */

	inline int NetworkConfiguration::getPortNumber() const
	{
		return mPortNumber;
	}

	inline int NetworkConfiguration::getFrequency() const
	{
		return mCachedFrequency;
	}

	inline void NetworkConfiguration::cacheFrequency(int frequency)
	{
		mCachedFrequency = frequency;
	}

	inline void NetworkConfiguration::resetCache()
	{
		mCachedFrequency = mFrequency;
	}

	inline bool NetworkConfiguration::fetchOnlyFreeServers() const
	{
		return mFetchOnlyFreeServers;
	}

	inline bool NetworkConfiguration::downloadUnknownLevels() const
	{
		return mDownloadUnknownLevels;
	}

	inline bool NetworkConfiguration::uploadLevels() const
	{
		return mUploadLevels;
	}

	inline ProxyConfiguration* NetworkConfiguration::getProxyConfiguration()
	{
		return mProxyConfiguration;
	}

	inline bool NetworkConfiguration::registerServer()
	{
		return mRegisterServer;
	}

/**
 * Configuration class
 */

	inline const wxString& Configuration::getLogoPath() const
	{
		return mLogoPath;
	}

	inline int Configuration::getDotSize() const
	{
		return mCachedDotSize;
	}

	inline void Configuration::cacheDotSize(int dotSize)
	{
		mCachedDotSize = dotSize;
	}

	inline void Configuration::resetCache(bool deepReset)
	{
		mCachedDotSize = mDotSize;
		if(false == deepReset)
			return;
		if(NULL != mNetworkConfiguration)
			mNetworkConfiguration->resetCache();
		if(NULL != mLevels)
		{
			std::vector<wxString> levelNames = mLevels->getLevelNames();

			for(unsigned int i = 0; i < levelNames.size(); i++)
			{
				mLevels->getLevel(levelNames[i])->getVehicleA()->resetCache();
				mLevels->getLevel(levelNames[i])->getVehicleB()->resetCache();
			}
		}
	}

	inline NetworkConfiguration* Configuration::getNetworkConfiguration()
	{
		return mNetworkConfiguration;
	}

	inline Levels* Configuration::getLevels()
	{
		return mLevels;
	}

/**
 * CommonConfigurationPacket class
 */

	inline int CommonConfigurationPacket::getDotSize()
	{
		return ntohl(mDotSize);
	}

	inline int CommonConfigurationPacket::getFrequency()
	{
		return ntohl(mFrequency);
	}

	inline wxPoint CommonConfigurationPacket::getVehiclePositionA()
	{
		return wxPoint(ntohl(mCoordinateAx), ntohl(mCoordinateAy));
	}

	inline wxPoint CommonConfigurationPacket::getVehiclePositionB()
	{
		return wxPoint(ntohl(mCoordinateBx), ntohl(mCoordinateBy));
	}
}

#endif /* CONFIGURATION_H_ */
